using System;
using System.ComponentModel;
using System.Configuration.Install;
using System.Xml;

namespace TKH.Biztalk.Diagnostics.Install
{
    [RunInstaller(true)]
    public partial class Installer : System.Configuration.Install.Installer
    {
        /// <summary>
        /// Installer constructor
        /// </summary>
        public Installer()
        {
            InitializeComponent();
        }

         /// <summary>
        /// We override Install so we can add diagnostic configuration to the BTSNTSvc.exe.config file.
        /// </summary>
        /// <param name="savedState"></param>
        public override void Install(System.Collections.IDictionary savedState)
        {
            AddToBTSNTSvcConfig();
        }

        /// <summary>
        /// We override Uninstall so we can remove diagnostic configuration to the BTSNTSvc.exe.config file.
        /// </summary>
        /// <param name="savedState"></param>
        public override void Uninstall(System.Collections.IDictionary savedState)
        {
            RemoveFromBTSNTSvcConfig(); 
        }

        /// <summary>
        /// Add configuration elements to BTSNTSvc.exe.config
        /// </summary>
        /// <param name="savedState"></param>
        public void AddToBTSNTSvcConfig()
        {
            string configPath = GetBTSNTSvcConfigPath();
            XmlDocument doc = new XmlDocument();
            doc.Load(configPath);

            XmlNode configDiagnostics = doc.SelectSingleNode("/configuration/system.diagnostics");
            if (configDiagnostics == null)
            {
                XmlElement element = doc.CreateElement("system.diagnostics");
                configDiagnostics = doc.DocumentElement.AppendChild(element);
            }
            XmlNode configTrace = configDiagnostics.SelectSingleNode("trace");
            if (configTrace == null)
            {
                XmlElement element = doc.CreateElement("trace");
                configTrace = configDiagnostics.AppendChild(element);
            }
            ((XmlElement)configTrace).SetAttribute("autoflush", "true");
            ((XmlElement)configTrace).SetAttribute("indentsize", "4");

            #region Sources 
            XmlNode configSources = configDiagnostics.SelectSingleNode("sources");
            if (configSources == null)
            {
                XmlElement element = doc.CreateElement("sources");
                configSources = configDiagnostics.AppendChild(element);
            }
            string sourceXPath = string.Format("source[@name = '{0}']", "BizTalk Orchestration");
            XmlNode configSource = configSources.SelectSingleNode(sourceXPath);
            if (configSource == null)
            {
                XmlElement element = doc.CreateElement("source");
                configSource = configSources.AppendChild(element);
            }
            ((XmlElement)configSource).SetAttribute("name", "BizTalk Orchestration");
            ((XmlElement)configSource).SetAttribute("switchValue", "Information");

            XmlNode configListeners = configSource.SelectSingleNode("listeners");
            if (configListeners == null)
            {
                XmlElement element = doc.CreateElement("listeners");
                configListeners = configSource.AppendChild(element);
            }
            else
            {
                configListeners.RemoveAll();
            }
            XmlElement listener = doc.CreateElement("add");
            listener.SetAttribute("name", "BiztalkTrace");
            configListeners.AppendChild(listener);
            listener = doc.CreateElement("add");
            listener.SetAttribute("name", "BiztalkLog");
            configListeners.AppendChild(listener);
            listener = doc.CreateElement("add");
            listener.SetAttribute("name", "BiztalkWMIEvents");
            configListeners.AppendChild(listener);
            
            #endregion

            #region Shared Listeners
            XmlNode configSharedlisteners = configDiagnostics.SelectSingleNode("sharedListeners");
            if (configSharedlisteners == null)
            {
                XmlElement element = doc.CreateElement("sharedListeners");
                configSharedlisteners = configDiagnostics.AppendChild(element);
            }
            //BiztalkTrace listener
            XmlNode configSharedBiztalkTrace = configSharedlisteners.SelectSingleNode("add[@name = 'BiztalkTrace']");
            if (configSharedBiztalkTrace == null)
            {
                XmlElement element = doc.CreateElement("add");
                configSharedBiztalkTrace = configSharedlisteners.AppendChild(element);
            }
            ((XmlElement)configSharedBiztalkTrace).SetAttribute("name", "BiztalkTrace");
            ((XmlElement)configSharedBiztalkTrace).SetAttribute("initializeData", @"c:\temp\BTSOrchestrationTrace.svclog");
            ((XmlElement)configSharedBiztalkTrace).SetAttribute("type", typeof(XmlTraceListener).AssemblyQualifiedName);
            ((XmlElement)configSharedBiztalkTrace).SetAttribute("traceOutputOptions", "Timestamp");
            //BiztalkLog listener
            XmlNode configSharedBiztalkLog = configSharedlisteners.SelectSingleNode("add[@name = 'BiztalkLog']");
            if (configSharedBiztalkLog == null)
            {
                XmlElement element = doc.CreateElement("add");
                configSharedBiztalkLog = configSharedlisteners.AppendChild(element);
            }
            ((XmlElement)configSharedBiztalkLog).SetAttribute("name", "BiztalkLog");
            ((XmlElement)configSharedBiztalkLog).SetAttribute("type", typeof(EventLogListener).AssemblyQualifiedName);
            ((XmlElement)configSharedBiztalkLog).SetAttribute("traceOutputOptions", "Timestamp");
            //BiztalkWMIEvents listener
            XmlNode configSharedBiztalkWmi = configSharedlisteners.SelectSingleNode("add[@name = 'BiztalkWMIEvents']");
            if (configSharedBiztalkWmi == null)
            {
                XmlElement element = doc.CreateElement("add");
                configSharedBiztalkWmi = configSharedlisteners.AppendChild(element);
            }
            ((XmlElement)configSharedBiztalkWmi).SetAttribute("name", "BiztalkWMIEvents");
            ((XmlElement)configSharedBiztalkWmi).SetAttribute("type", typeof(WMIEventListener).AssemblyQualifiedName);
            ((XmlElement)configSharedBiztalkWmi).SetAttribute("traceOutputOptions", "Timestamp");
            #endregion

            //write machine.config
            XmlTextWriter writer = new XmlTextWriter(configPath, null);
            writer.Formatting = Formatting.Indented;
            doc.Save(writer);
            writer.Close();

        }

        /// <summary>
        /// Remove configuration elements from BTSNTSvc.exe.config
        /// </summary>
        /// <param name="savedState"></param>
        public void RemoveFromBTSNTSvcConfig()
        {
            string configPath = GetBTSNTSvcConfigPath();
            XmlDocument doc = new XmlDocument();
            doc.Load(configPath);

            XmlNode configDiagnostics = doc.SelectSingleNode("/configuration/system.diagnostics");
            if (configDiagnostics != null)
            {
                XmlNode configSources = configDiagnostics.SelectSingleNode("sources");
                if (configSources != null)
                {   //Quote and Sale
                    string sourceXPath = string.Format("source[@name = '{0}']", "BiztalkDiagnostics");
                    XmlNode configSource = configSources.SelectSingleNode(sourceXPath);
                    if (configSource != null)
                    {
                        configSources.RemoveChild(configSource);
                    }
                    if (!configSources.HasChildNodes)
                    {
                        configDiagnostics.RemoveChild(configSources);
                    }
                }
                XmlNode configsharedListeners = configDiagnostics.SelectSingleNode("sharedListeners");
                if (configsharedListeners != null)
                {
                    foreach(string name in new string[]{"BiztalkTrace", "BiztalkLog", "BiztalkWMIEvents"})
                    {
                        XmlNode node = configsharedListeners.SelectSingleNode(string.Format("add[@name = '{0}']", name));
                        node = node != null ? configsharedListeners.RemoveChild(node) : null; 
                    }
                    if (!configsharedListeners.HasChildNodes)
                    {
                        configDiagnostics.RemoveChild(configsharedListeners);
                    }
                }
                if (!configDiagnostics.HasChildNodes)
                {
                    doc.DocumentElement.RemoveChild(configDiagnostics);
                }
                
            }
            ////write machine.config
            XmlTextWriter writer = new XmlTextWriter(configPath, null);
            writer.Formatting = Formatting.Indented;
            doc.Save(writer);
            writer.Close();
        }

        /// <summary>
        /// Gets path to BTSNTSvc.exe.config from registry
        /// </summary>
        /// <returns>Path to </returns>
        internal static string GetBTSNTSvcConfigPath()
        {
            object installRoot = Microsoft.Win32.Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\BizTalk Server\3.0\NTService", "ExeImagePath", null);
            if (installRoot == null)
            {
                throw new Exception("Unable to retrieve install root for .NET framework");
            }

            return string.Format(@"{0}.config", installRoot.ToString());
        }
    }
}